#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<string.h>
#include<pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#define LOCAL_LISTEN_PORT 8080
typedef struct mh   //38字节的命令头部信息，并且提供一个标志为表示该信息是否是正确的信息
{
	char vaild;  //标记此头部信息是否合法 ,0表示不是要转发，1为转发
	unsigned char dstIP[20];  //xxx.xxx.xxx.xxx
	unsigned short int port;
	char token[32];
	int socket_remote;  //记录发来数据的socket
	int socket_srv;  //记录要服务端的socket
	char rawdata[38];  //用于存储接收到的38字节首部原始数据
} MarkHead;

void* SrvToClient_thread(void* para);  //通讯线程，服务端往客户端数据流线程。
void* ClientToSrv_thread(void* para);  //通讯线程，客户端往服务端数据流线程。
MarkHead CheckHeadMark(char*headmark);     //检查初始链接进来本地的客户端发来的头38个字节数据是否合法，并解析,返回一个MarkHead
//结构体变量。
int main(int argc,char** argv)
{

	char headmark[38]= {0}; // 用于标识转发信息的头部数据包
	MarkHead mh_data= {0};
	//1.create socket
	int s=socket(AF_INET,SOCK_STREAM,0);
	if(-1==s)
	{
		printf("create socket error\n");
		return 0;
	}
	//2.prepare a socet_addr
	struct sockaddr_in SrvAddr;
	SrvAddr.sin_family=AF_INET;
	SrvAddr.sin_port=htons(LOCAL_LISTEN_PORT);
	SrvAddr.sin_addr.s_addr=INADDR_ANY;
	//3.bind address
	int ret=bind(s,(struct sockaddr*)&SrvAddr,sizeof(struct sockaddr_in));
	if(-1==ret)
	{
		printf("bind socket error\n");
		return 0;
	}
	else
		printf("bind success on :%d\n",LOCAL_LISTEN_PORT);
	//4.begin listen
	ret=listen(s,10);
	if(-1==ret)
	{
		printf("listen socket error\n");
		return 0;
	}
	//	else printf("listen success::8005\n");
	//5.prepare a client socket
	struct sockaddr_in sacc;
	int len_sacc=sizeof(struct sockaddr_in);
	int client;
	//6.begin while to accept client
	pthread_t tid;
	int RecvTimeOut=120*1000;
	int SendTimeOut=120*1000;
	int err;

	while(1)
	{
		printf("begin accept...\n");
		client=accept(s,(struct sockaddr*)&sacc,&len_sacc);
		printf("accept one connectino\n");
		if(-1==client)
		{
			printf("accept socket error\n");
			return 0;
		}
		else
		{
			printf("begin a now session:%d\n",client);
			printf("checking mark_head data...\n");
			bzero(headmark,38);
			//recv(client,headmark,38,MSG_PEEK|MSG_DONTWAIT);
			recv(client,headmark,38,MSG_PEEK);
			/*if(-1==recv(client,headmark,38,MSG_PEEK))
			{
				printf("peek  head mark error\n");    //接受头数据信息
				return 0;
			}*/
			mh_data=CheckHeadMark(headmark);	//检查头部数据信息并解析
			printf("check head mark result:%s:%d\n",mh_data.dstIP,mh_data.port);


			mh_data.socket_remote=client;
			int sock_srv=socket(AF_INET,SOCK_STREAM,0);
			struct sockaddr_in addr_srv;
			addr_srv.sin_family=AF_INET;
			addr_srv.sin_port=htons(mh_data.port);
			addr_srv.sin_addr.s_addr=inet_addr(mh_data.dstIP);

			if(-1==connect(sock_srv,(struct sockaddr*)&addr_srv,sizeof(struct sockaddr)))
			{
				printf("connect to srv error\n");
				return 0;
			}
			mh_data.socket_srv=sock_srv;

			setsockopt(mh_data.socket_remote,SOL_SOCKET,SO_RCVTIMEO,(char*)&RecvTimeOut,sizeof(int));
			setsockopt(mh_data.socket_remote,SOL_SOCKET,SO_SNDTIMEO,(char*)&SendTimeOut,sizeof(int));
			setsockopt(mh_data.socket_srv,SOL_SOCKET,SO_RCVTIMEO,(char*)&RecvTimeOut,sizeof(int));
			setsockopt(mh_data.socket_srv,SOL_SOCKET,SO_SNDTIMEO,(char*)&SendTimeOut,sizeof(int));

			//开始转发流程，跟据mh_data.valid标志来确定是否要发送首部数据raw_data到srv端
			err=pthread_create(&tid,NULL,ClientToSrv_thread,(void*)&mh_data);
			err=pthread_create(&tid,NULL,SrvToClient_thread,(void*)&mh_data);

		}

	}
	close(s);

	return 0;
}
void* SrvToClient_thread(void* para)
{
	MarkHead mh;
	memcpy(&mh,(MarkHead*)para,sizeof(MarkHead));
	//	printf(" Client-->srv thread,socket client=%d\t,socket srv=%d\n",client,srv);
	char BuffClientRcv[1024*4]= {0};
	char BuffSrvRcv[1024*4]= {0};
	int RcvBytes=0;
	int SendBytes=0;
	printf("begin to recv data from :%d\n",mh.socket_srv);
	while((RcvBytes=recv(mh.socket_srv,BuffClientRcv,1024*4,0))!=-1&&RcvBytes!=0)
	{
		printf("get data from srv:%d\n",RcvBytes);
		SendBytes=send(mh.socket_remote,BuffClientRcv,RcvBytes,0); //send to client
		memset(BuffClientRcv,0,1024*4);
	}

	printf("srv recv error,RcvBytes=%d\n",RcvBytes);
	close(mh.socket_remote);
	close(mh.socket_srv);
	return ;


}
void* ClientToSrv_thread(void* para)
{
	MarkHead mh;
	memcpy(&mh,(MarkHead*)para,sizeof(MarkHead));
	//	printf(" Client-->srv thread,socket client=%d\t,socket srv=%d\n",client,srv);
	char BuffClientRcv[1024*4]= {0};
	char BuffSrvRcv[1024*4]= {0};
	int RcvBytes=0;
	int SendBytes=0;
	/*if(0==mh.vaild)
	  {
	  send(mh.socket_srv,mh.rawdata,38,0);   //如果是默认转发，需要吧之前接收的首部38字节发送
	  printf("send head data success!\n");
	  }*/
	printf("begin to recv data from :%d\n",mh.socket_remote);

	while((RcvBytes=recv(mh.socket_remote,BuffClientRcv,1024*4,0))!=-1&&RcvBytes!=0)
	{
		printf("get data from client:%d\n",RcvBytes);
		SendBytes=send(mh.socket_srv,BuffClientRcv,RcvBytes,0); //send to srv
		memset(BuffClientRcv,0,1024*4);
	}
	printf("client recv error,RcvBytes=%d\n",RcvBytes);
	close(mh.socket_remote);
	close(mh.socket_srv);
	return ;


}

MarkHead CheckHeadMark(char* headmark) //38bytes data,
{
	int i=0;
	printf("get head rawdata:");
	for(i=0;i<38;i++)
	{
		printf("%d ",headmark[i]);
	}
	printf("\n");
	unsigned char buf[38]={0};
	unsigned char portbuf[2]={0};

	MarkHead mark;
	mark.vaild=0;
	strcpy(mark.dstIP,"127.0.0.1");
	mark.port=22;
	memcpy(buf,headmark,38);
	if(memcmp(buf+6,"b60d84d4168a2bf7ced43dcf29e7b18e",32)!=0) //首先比较token是否一致,不一致则填写默认转发信息直接返回。标记无需转发.
	{
		printf("vaild head mark,go to normal connection\n");
		mark.vaild=0;
		return mark;
	}
	else                         //如果token验证成功，则表示一致，需要开始解析
	{
		sprintf(mark.dstIP,"%u.%u.%u.%u",buf[0],buf[1],buf[2],buf[3]);
		printf("parse headmark IP:%s\n",mark.dstIP);
		memcpy(portbuf,buf+4,2);
		mark.port=portbuf[0]*256+portbuf[1];
		strcpy(mark.token,"b60d84d4168a2bf7ced43dcf29e7b18e");
		memcpy(mark.rawdata,headmark,38);
		printf("complete parse headmark,IP=%s,PORT=%d,token=%s\n",mark.dstIP,mark.port,mark.token);
		mark.vaild=1;  //解析成功，需要做转发处理
		return mark;
	}


}


